package cn.zo01.my_server.controller;

import cn.zo01.my_server.common.result.Result;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Stream;

@Slf4j
@RestController
@RequestMapping("/common")
public class CommonController {

    @Value("${my_server.path}")
    private String path;

    /**
     * 单文件上传
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public Result<String> upload(
            @RequestParam("file")MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        assert originalFilename != null;
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        String  uuid = UUID.randomUUID().toString();
        String fileName = uuid + suffix;

        File dir = new File(path);
        if (!dir.exists()){
            dir.mkdirs();
        }
        try {
            file.transferTo(new File(dir, fileName));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return Result.ok(fileName);
    }

    /**
     * 多文件上传
     * @param files
     * @return
     */
    @PostMapping("/multi")
    public Result<List<String>> uploadMultipleFiles(
            @RequestParam("files") MultipartFile[] files) {
        if (files == null || files.length == 0) {
            return Result.fail(0,"请选择至少一个文件上传");
        }

        File dir = new File(path);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        List<String> fileNames = new ArrayList<>();
        for (MultipartFile file : files) {
            try {
                String originalFilename = file.getOriginalFilename();
                String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
                String uuid = UUID.randomUUID().toString();
                String fileName = uuid + suffix;

                file.transferTo(new File(dir, fileName));
                fileNames.add(fileName);
            } catch (IOException e) {
                log.error("文件上传失败: {}", file.getOriginalFilename(), e);
                // 可以选择继续处理其他文件或直接返回错误
                return Result.fail(0,"文件 " + file.getOriginalFilename() + " 上传失败");
            }
        }
        return Result.ok(fileNames);
    }

    /**
     * 分片上传
     * @param fileId 前端生成的
     * @param chunks 总的分片数
     * @param fileName 原始文件名
     * @return
     */
    @PostMapping("/chunk/init")
    public Result<Map<String, Object>> initChunkUpload(
            @RequestParam("fileId") String fileId,
            @RequestParam("chunks") int chunks,
            @RequestParam("fileName") String fileName) {
        // 创建临时目录存放分片
        String tempDir = path + File.separator + "temp" + File.separator + fileId;
        File dir = new File(tempDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 返回给前端的信息
        Map<String, Object> result = new HashMap<>();
        result.put("fileId", fileId);
        result.put("chunks", chunks);
        result.put("tempDir", tempDir);

        return Result.ok(result);
    }

    /**
     * 分片上传 - 上传分片
     * @param file
     * @param chunkNumber
     * @param fileId
     * @return
     */
    // 大文件分片上传 - 上传分片
    @PostMapping("/chunk")
    public Result<String> uploadChunk(
            @RequestParam("file") MultipartFile file,
            @RequestParam("chunkNumber") int chunkNumber,
            @RequestParam("fileId") String fileId) {

        String tempDir = path + File.separator + "temp" + File.separator + fileId;
        File dir = new File(tempDir);
        if (!dir.exists()) {
            return Result.fail(0,"请先初始化上传");
        }

        try {
            // 保存分片文件，命名为chunkNumber
            String chunkFileName = chunkNumber + ".part";
            file.transferTo(new File(dir, chunkFileName));
            return Result.ok("分片上传成功");
        } catch (IOException e) {
            log.error("分片上传失败", e);
            return Result.fail(0,"分片上传失败");
        }
    }
    // 大文件分片上传 - 合并分片
    @PostMapping("/chunk/merge")
    public Result<String> mergeChunks(
            @RequestParam("fileId") String fileId,
            @RequestParam("fileName") String originalFileName) {

        String tempDir = path + File.separator + "temp" + File.separator + fileId;
        File dir = new File(tempDir);
        if (!dir.exists()) {
            return Result.fail(0,"找不到分片文件目录");
        }

        // 获取所有分片文件并按序号排序
        File[] chunkFiles = dir.listFiles();
        if (chunkFiles == null || chunkFiles.length == 0) {
            return Result.fail(0,"没有找到分片文件");
        }

        // 按分片序号排序
        Arrays.sort(chunkFiles, Comparator.comparingInt(f -> Integer.parseInt(f.getName().split("\\.")[0])));

        // 生成最终文件名
        String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));
        String uuid = UUID.randomUUID().toString();
        String fileName = uuid + suffix;
        File outputFile = new File(path, fileName);

        try {
            // 合并文件
            try (OutputStream outputStream = Files.newOutputStream(outputFile.toPath())) {
                for (File chunkFile : chunkFiles) {
                    Files.copy(chunkFile.toPath(), outputStream);
                }
            }

            // 删除临时目录
            deleteDirectory(tempDir);

            return Result.ok(fileName);
        } catch (IOException e) {
            log.error("合并文件失败", e);
            return Result.fail(0,"合并文件失败");
        }
    }

    // 删除目录及其内容
    private void deleteDirectory(String dirPath) throws IOException {
        Path directory = Paths.get(dirPath);
        try (Stream<Path> walk = Files.walk(directory)) {
            walk.sorted(Comparator.reverseOrder())
                    .map(Path::toFile)
                    .forEach(File::delete);
        }
    }


    /**
     * 文件下载
     * @param response
     * @param fileName
     */
    @GetMapping("/download")
    public void download(
            HttpServletResponse response,
            @RequestParam("fileName") String fileName){
        File file = new File(path, fileName);

        try{
            FileInputStream fileInputStream = new FileInputStream(file);
            ServletOutputStream outputStream = response.getOutputStream();
            response.setContentType("image/jpeg");
            int len = 0;
            byte[] buffer = new byte[1024];
            while((len = fileInputStream.read(buffer)) != -1){
                outputStream.write(buffer, 0, len);
                outputStream.flush();
            }
            outputStream.close();
            fileInputStream.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
